/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.actions.zip;

import com.softwarecraftsmen.orogeny.buildLogs.BuildLog;
import static com.softwarecraftsmen.orogeny.buildLogs.Verbosity.Summary;
import com.softwarecraftsmen.orogeny.filing.AbsoluteFile;
import com.softwarecraftsmen.archivers.zip.zipEntryAndData.ExistingZipEntryBackedZipEntryAndData;
import com.softwarecraftsmen.archivers.zip.zipEntryAndData.ZipEntryAndData;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import static java.lang.String.format;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import static java.util.Locale.UK;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public final class InputZipIterator implements Iterator<ZipEntryAndData>
{
	private final Iterator<AbsoluteFile> inputZipsIterator;
	private final Set<String> seenBeforeZipEntries;
	private ZipFile currentInputZip;
	private Iterator<ExistingZipEntryBackedZipEntryAndData> currentEntries;
	private final BuildLog buildLog;
	private final ZipEntryFilter zipEntryFilter;

	public InputZipIterator(final @NotNull BuildLog buildLog, final @NotNull Set<AbsoluteFile> inputZips)
	{
		this.buildLog = buildLog;
		inputZipsIterator = inputZips.iterator();
		seenBeforeZipEntries = new LinkedHashSet<>();
		currentInputZip = null;
		currentEntries = null;
		zipEntryFilter = new ZipEntryFilter(this.buildLog);
	}

	public boolean hasNext()
	{
		if (currentInputZip == null)
		{
			if (!inputZipsIterator.hasNext())
			{
				return false;
			}
			currentEntries = processInputZip(inputZipsIterator.next());
		}
		if (!currentEntries.hasNext())
		{
			currentEntries = null;
			try
			{
				currentInputZip.close();
			}
			catch (IOException e)
			{
				throw new IllegalStateException(e);
			}
			currentInputZip = null;
			return hasNext();
		}
		else
		{
			return true;
		}
	}

	@NotNull
	public ZipEntryAndData next()
	{
		if (currentInputZip == null || currentEntries == null)
		{
			throw new NoSuchElementException();
		}
		return currentEntries.next();
	}

	public void remove()
	{
		throw new UnsupportedOperationException("Ridiculous");
	}

	@SuppressWarnings({"ThrowFromFinallyBlock"})
	private Iterator<ExistingZipEntryBackedZipEntryAndData> processInputZip(final AbsoluteFile inputZipFile)
	{
		buildLog.writeMessage(Summary, format(UK, "Processing zip %1$s", inputZipFile));
		currentInputZip = inputZipFile.openAsZipFile();
		return new ArrayList<ExistingZipEntryBackedZipEntryAndData>()
		{{
			for (ZipEntry usefulZipEntry : zipEntryFilter.usefulZipEntries(currentInputZip, seenBeforeZipEntries))
			{
				add(new ExistingZipEntryBackedZipEntryAndData(usefulZipEntry, currentInputZip));
			}
		}}.iterator();
	}

}
